package com.weiter.common.core.aspect;

import com.alibaba.fastjson2.JSON;
import com.weiter.common.core.annotation.PrintParameter;
import com.weiter.common.core.utils.ServletUtils;
import com.weiter.common.core.utils.ip.IpUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * 打印参数注解
 * @author weiter
 **/
@Aspect
@Component
public class PrintParameterAspect {

    private static final Logger log = LoggerFactory.getLogger(PrintParameterAspect.class);

    @Pointcut(value = "@annotation(com.weiter.common.core.annotation.PrintParameter)")
    public void printParameter() {
    }

    @Around(value = "printParameter()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 从上下文获取请求路由
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        // 获取远程主机ip
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        PrintParameter methodAnnotation = method.getAnnotation(PrintParameter.class);
        Object[] args = joinPoint.getArgs();
        args = Arrays.stream(args).filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse))).toArray();
        // 方法执行开始
        long start = System.currentTimeMillis();
        if (methodAnnotation.printInParameter()) {
            log.info("远程主机IP:{},请求路径:{},请求入参：{}", ip, request.getRequestURI(), JSON.toJSONString(args));
        }

        Object result = joinPoint.proceed();
        long executeTime = System.currentTimeMillis() - start;
        if (methodAnnotation.printOutParameter()) {
            log.info("远程主机IP:{},请求路径:{},请求出参：{}", ip, request.getRequestURI(), JSON.toJSONString(result));
        }
        log.info("远程主机IP:{},请求路径:{},执行结束，耗时:{} 毫秒", ip, request.getRequestURI(), executeTime);
        return result;
    }
}
